package com.asynccommand.framework;

import java.util.Map;

public abstract class BaseCommand {

	public static final String RESULT_CODE = "resultcode";
	public static final String OK = "ok";
	public static final String ERROR = "error";
	public static final String ERROR_MSG = "errormsg";

	/**
	 * Devuelve el identificador del comando.
	 * 
	 * @return
	 */
	public abstract int getID();

	/**
	 * Debe utilizarse para configurar el comando antes de ejecutarse
	 * 
	 * @param params
	 */
	protected abstract void setup(Map<String, Object> params);

	/**
	 * El proceso asincronico que el command ejecturá.
	 * 
	 * @return
	 */
	protected abstract Map<String, Object> job();

	/**
	 * Proceso que se ejecuta luego de ejecutarse job().
	 * 
	 * @param resultSet
	 * @return
	 */
	protected abstract Map<String, Object> processResult(
			Map<String, Object> resultSet);

	private void requestStarted() {
		CommandsController.get().changeRequestState(getID(),
				CommandsController.State.STATE_INPROGRESS, null);
	}

	private void requestError(Map<String, Object> resultSet) {
		CommandsController.get().changeRequestState(getID(),
				CommandsController.State.STATE_ERROR, resultSet);
	}

	private void requestComplete(Map<String, Object> resultSet) {
		CommandsController.get().changeRequestState(getID(),
				CommandsController.State.STATE_DONE, resultSet);
	}

	/**
	 * Llama al setup() del command y ejecuta job() en forma asincronica.
	 * 
	 * @param params
	 */
	public final void execute(Map<String, Object> params) {
		setup(params);
		AsyncRequestExecutor executer = new AsyncRequestExecutor();
		executer.run();
	}

	/**
	 * Llama al setup() del command y ejecuta job() en forma asincronica.
	 * 
	 */
	public final void execute() {
		execute(null);
	}

	private class AsyncRequestExecutor extends Thread {

		@Override
		public void run() {
			requestStarted();
			Map<String, Object> resultSet = job();
			if (((String) resultSet.get(RESULT_CODE)).equalsIgnoreCase(OK)) {
				resultSet = processResult(resultSet);
				if (((String) resultSet.get(RESULT_CODE)).equalsIgnoreCase(OK)) {
					requestComplete(resultSet);
				} else {
					requestError(resultSet);
				}
			} else {
				requestError(resultSet);
			}
		}
	}

}